import datetime
import logging
import pandas as pd
import numpy as np
import tabula as tb
from pathlib import Path

from coin.exchange.kr_rest.product.product_impl import generate_product_from_str2


class BinanceSpotParser(object):
  def __init__(self, score_root_dir):
    self._score_root_dir = score_root_dir

  def parse_rqmt(self, rqmt_path):
    df_list = tb.read_pdf(rqmt_path, pages='all', pandas_options={'header': None})
    native_symbols = []
    weights = []
    for i in range(2):
      for _, row in df_list[i].iterrows():
        if pd.notnull(row[0]) and row[0].isupper() and pd.notnull(row[5]):
          native_symbols.append(row[0])
          weight = float(row[5]) if i == 0 else float(row[6])
          weights.append(weight)
    symbol = [generate_product_from_str2(
        'Spot', 'Binance', 'v1', ns).symbol for ns in native_symbols]
    return dict(zip(symbol, weights))

  def parse_daily_score(self, trading_date):
    file_path = f'{self._score_root_dir}/daily_score_{trading_date.strftime("%Y%m%d")}.pdf'
    df_list = tb.read_pdf(file_path, pages='all', pandas_options={'header': None})
    df = df_list[0]
    if isinstance(df.iloc[0, 5], str): df = df.drop([0])
    df[[0, 1]] = df[0].str.split(' ', 1, expand=True)
    df.loc[df[1] == 'N/A', 1] = np.nan
    df[2] = df[2].str.replace(',', '').astype(float)
    df[3] = df[3].str.replace(',', '').astype(float)
    df[4] = df[4].str.replace('%', '').astype(float) / 100
    df[5] = df[5].astype(float)
    df.columns = ['native_symbol', 'pair_rank', 'score',
                  'maker_volume(USDT)', 'qualified_ratio', 'weight']
    df['score'] = df['score'].fillna(0)
    df['qualified_ratio'] = df['qualified_ratio'].fillna(0)
    df['symbol'] = [generate_product_from_str2(
        'Spot', 'Binance', 'v1', symbol).symbol for symbol in df['native_symbol']]
    df_scores = df.copy()
    scores = tb.read_pdf(file_path, pages='all', area=[
                         500, 40, 580, 340], stream=True, pandas_options={'header': None})
    df = scores[0]
    df[[0, 1]] = df[0].str.split(': ', 1, expand=True)
    df[0] = [k.lower().replace(" ", "_") for k in df[0]]
    scores_info = dict(zip(df[0], df[1]))
    return df_scores, scores_info


class BinanceCoinMarginedFuturesParser(object):
  def __init__(self, score_root_dir):
    self._score_root_dir = score_root_dir
    self._rqmt_release_date = None

  def parse_rqmt(self, rqmt_path):
    df_list = tb.read_pdf(rqmt_path, pages='all', pandas_options={'header': None})
    native_symbols = []
    weights = []
    for df in df_list:
      if df.shape[1] in (6, 7,):
        filtered = df.loc[(df.iloc[:, -1].notnull()) &
                          (~df.iloc[:, -1].isin(['Updated', 'Weight']))]
        native_symbols += list(filtered.iloc[:, 0])
        weights += list(filtered.iloc[:, -1])
    weights = list(map(float, weights))
    release_date_str = Path(rqmt_path).stem[-8:]
    release_date = datetime.datetime.strptime(release_date_str, '%Y%m%d').date()
    self._rqmt_release_date = release_date
    symbols = []
    for ns in native_symbols:
      try:
        product = generate_product_from_str2(
            'Futures', 'Binance', 'v1-delivery', ns,
            current_datetime=self._rqmt_release_date)
        symbols.append(product.symbol)
      except:
        logging.info('Fail to generate product in parse req: %s'% ns)
    return dict(zip(symbols, weights))

  def parse_daily_score(self, trading_date):
    file_path = f'{self._score_root_dir}/daily_score_{trading_date.strftime("%Y%m%d")}.pdf'
    df_list = tb.read_pdf(file_path, pages='all', pandas_options={'header': None})
    df = df_list[0]
    native_symbol_list = df[0]
    if df[4].isnull().all():
      qualif_ratio_list = df[5]
    else:
      qualif_ratio_list = df[4] if df[4][0].endswith('%') else df[5]
    func = lambda x: generate_product_from_str2(
        'Futures', 'Binance', 'v1-delivery', x,
        current_datetime=self._rqmt_release_date).symbol
    symbol_list = native_symbol_list.apply(func)
    df_scores = pd.concat([symbol_list, qualif_ratio_list], axis=1)
    df_scores.columns = ['symbol', 'qualified_ratio']
    df_scores['qualified_ratio'] = df_scores['qualified_ratio'].str.replace(
        '%', '').astype(float) / 100
    scores = tb.read_pdf(file_path, pages='all', area=[
                         400, 40, 660, 400], stream=True, pandas_options={'header': None})
    df = scores[0]
    df[[0, 1]] = df[0].str.split(': ', 1, expand=True)
    keys = ['daily_maker_score',
            'daily_ranking',
            'cumultative_weekly_maker_score',
            'cumulative_weekly_ranking',
            'daily_total_maker_volume',
            'daily_total_maker_volume_pct',
            'cumultative_weekly_total_maker_volume',
            'cumultative_weekly_total_maker_volume_pct']
    values = [d for d in df[1] if d is not None]
    scores_info = dict(zip(keys, values))
    return df_scores, scores_info
